<template>
  <div class="common-editor" style="background-color: rgba(255, 255, 255, 0.6);">
    <div style="margin-bottom: 12px;">
      <strong>主题：</strong>
      <Select v-model="them" placeholder="请选择" style="width: 175px">
        <Option
          v-for="item in thems"
          :key="item.value"
          :label="item.label"
          :value="item.value"
          @click.native="changeTheme(item.label)">
        </Option>
      </Select>&emsp;
      <strong>字体：</strong>
      <Select v-model="font" placeholder="请选择" style="width: 175px">
        <Option
          v-for="item in fonts"
          :key="item.value"
          :label="item.label"
          :value="item.value"
          @click.native="changeFont(item.label)">
        </Option>
      </Select>&emsp;
      <strong>语言：</strong>
      <Select v-model="lang" placeholder="请选择" style="width: 175px">
        <Option
          v-for="item in langs"
          :key="item.value"
          :label="item.label"
          :value="item.value"
          @click.native="changeMode(item.label)">
        </Option>
      </Select>&emsp;
      <Button type="primary" plain style="float: right" @click="commit">提交</Button>
      <Button style="float: right; margin-right: 5px" @click="debug">调试</Button>
    </div>
    <textarea ref="textarea" v-model="value"></textarea>
    <div style="width: 100%; text-align: left; display: inline-flex">
      <div style="width: 48%; margin: 9px; font-weight: bold; font-size: 15px">
        <strong style="margin: 3px">输入（调试）：</strong>
        <Input
          v-model="debugInput"
          :autosize="{ minRows: 3, maxRows: 10 }"
          type="textarea"
          placeholder="输入...."
        />
      </div>
      <div style="width: 48%; margin: 8px; font-weight: bold; font-size: 15px;">
        <strong style="margin: 3px">输出（调试）：</strong>
        <Input
          v-model="debugOutput"
          :autosize="{ minRows: 3, maxRows: 10 }"
          disabled
          type="textarea"
          placeholder="输出..."
        />
      </div>
    </div>
  </div>
</template>

<script>
import 'codemirror/theme/material.css'
import 'codemirror/theme/monokai.css'
import 'codemirror/theme/darcula.css'
import 'codemirror/theme/idea.css'
import 'codemirror/theme/mdn-like.css'
import 'codemirror/theme/duotone-light.css'

import 'codemirror/lib/codemirror.css'
import 'codemirror/addon/hint/show-hint.css'
import 'codemirror/addon/hint/show-hint.js'
import 'codemirror/addon/hint/show-hint'
import 'codemirror/addon/hint/javascript-hint'
import 'codemirror/addon/hint/sql-hint'
import 'codemirror/mode/javascript/javascript'
import 'codemirror/mode/markdown/markdown'
import 'codemirror/mode/clike/clike'
import 'codemirror/mode/sql/sql'
import 'codemirror/mode/php/php'
import 'codemirror/mode/python/python'
import 'codemirror/mode/shell/shell'
import 'codemirror/mode/powershell/powershell'
import {debugCode, saveCommit} from "../../api/oj/commit";
import { MessageBox } from "element-ui";
import { getToken } from '@/utils/auth'
import { Input } from "element-ui";

const CodeMirror = require('codemirror/lib/codemirror')

export default {
  components: { MessageBox },
  name: 'CommonEditor',
  props: {
    value: {
      type: String,
      default: 'import java.util.*;\n' +
        '\n' +
        'public class Main {\n' +
        '    public static void main(String[] args) {\n' +
        '        Scanner scanner = new Scanner(System.in);\n' +
        '        \n' +
        '        System.out.println();\n' +
        '    }\n' +
        '}',
    },
    language: {
      type: String,
      default: 'Java'
    }
  },
  data() {
    return {
      debugInput: '',
      debugOutput: '',
      phpCode: '<?php\n' +
        '$line = fgets(STDIN);          // 读取一行输入\n' +
        '$data = explode(\' \', $line);   // 空格分隔数据\n' +
        '\n' +
        'echo \'\';',
      javaCode: 'import java.util.*;\n' +
        '\n' +
        'public class Main {\n' +
        '    public static void main(String[] args) {\n' +
        '        Scanner scanner = new Scanner(System.in);\n' +
        '        \n' +
        '        System.out.println();\n' +
        '    }\n' +
        '}',
      lang: 1,
      langs: [
        {
          label: "Java",
          value: 1,
        },
        {
          label: "PHP",
          value: 2,
        },
      ],
      font: 18,
      fonts: [
        {
          label: "12px",
          value: 12,
        },
        {
          label: "14px",
          value: 14,
        },
        {
          label: "16px",
          value: 16,
        },
        {
          label: "18px",
          value: 18,
        },
        {
          label: "20px",
          value: 20,
        },
        {
          label: "22px",
          value: 22,
        },
        {
          label: "24px",
          value: 24,
        },
      ],
      them: "material",
      thems: [
        {
          label: "material",
          value: "material",
        },
        {
          label: "monokai",
          value: "monokai",
        },
        {
          label: "darcula",
          value: "darcula",
        },
        {
          label: "idea",
          value: "idea",
        },
        {
          label: "mdn-like",
          value: "mdn-like",
        },
        {
          label: "duotone-light",
          value: "duotone-light",
        },
      ],
      CommonEditor: false,
      coder: null,
      theme: 'default',
      modes: [
        { value: 'x-java', label: 'Java' },
        { value: 'x-php', label: 'PHP' },
      ]
    }
  },
  watch: {
    language: {
      handler(language) {
        this.getCoder().then(() => {
          // 尝试从父容器获取语法类型
          if (language) {
            // 获取具体的语法类型对象
            const modeObj = this.getLanguage(language)
            // 判断父容器传入的语法是否被支持
            if (modeObj) {
              this.mode = modeObj.label
              this.coder.setOption('mode', `text/${modeObj.value}`)
            }
          }
        })
      },
      immediate: true
    }
  },
  computed: {
    coderOptions() {
      return {
        mode: 'Java',
        theme: 'material',
        tabSize: 4,
        indentUnit: 4,
        lineNumbers: true,
        electricChars: false,
        hintOptions: {
          completeSingle: false,
        },
      }
    }
  },
  mounted() {
    // 初始化
    this.initialize()
    var cs = document.getElementsByClassName('CodeMirror');
    for(var i = 0; i < cs.length; i++) {
      cs[i].style.fontSize = '18px';
    }
  },
  methods: {
    // 初始化
    initialize() {
      // 初始化编辑器实例，传入需要被实例化的文本域对象和默认配置
      this.coder = CodeMirror.fromTextArea(
        this.$refs.textarea,
        this.coderOptions
      )
      this.coder.on('inputRead', () => {
        this.coder.showHint()
      })
      // 编辑器赋值
      if (this.value || this.code) {
        this.setCodeContent(this.value || this.code)
      } else {
        this.coder.setValue('')
      }
      // 支持双向绑定
      this.coder.on('change', (coder) => {
        this.code = coder.getValue()
        if (this.$emit) {
          this.$emit('input', this.code)
        }
      })
    },
    setCodeContent(val) {
      setTimeout(() => {
        if (!val) {
          this.coder.setValue('')
        } else {
          this.coder.setValue(val)
        }
      }, 300)
    },
    getCoder() {
      const that = this
      return new Promise((resolve) => {
        ;(function get() {
          if (that.coder) {
            resolve(that.coder)
          } else {
            setTimeout(get, 10)
          }
        })()
      })
    },
    getLanguage(language) {
      // 在支持的语法类型列表中寻找传入的语法类型
      return this.modes.find((mode) => {
        // 所有的值都忽略大小写，方便比较
        const currentLanguage = language.toLowerCase()
        const currentLabel = mode.label.toLowerCase()
        const currentValue = mode.value.toLowerCase()

        // 由于真实值可能不规范，例如 java 的真实值是 x-java ，所以讲 value 和 label 同时和传入语法进行比较
        return (
          currentLabel === currentLanguage || currentValue === currentLanguage
        )
      })
    },
    changeFont(val) {
      var cs = document.getElementsByClassName('CodeMirror');
      for(var i = 0; i < cs.length; i++) {
        cs[i].style.fontSize = val;
      }
    },
    changeTheme(val) {
      this.coder.setOption('theme', val);
    },
    changeMode(val) {
      console.log(this.coder);
      if(val === 'Java') {
        this.lang = 1;
        this.coder.setValue(this.javaCode);
      }
      if(val === 'PHP') {
        this.lang = 2;
        this.coder.setValue(this.phpCode);
      }
      // 修改编辑器的语法配置
      this.coder.setOption('mode', `text/${this.getLanguage(val).value}`)
      // 获取修改后的语法
      const label = this.getLanguage(val).label.toLowerCase()
      // 允许父容器通过以下函数监听当前的语法值
      this.$emit('language-change', label)
    },
    debug() {
      this.$Spin.show({
        render: (h) => {
          return h("div", [
            h("Icon", {
              class: "demo-spin-icon-load",
              props: {
                type: "ios-loading",
                size: 50,
              },
            }),
            h("div", { class: "textSty" }, "代码正在努力运行中"),
          ]);
        },
      });
      debugCode(this.$route.query.id, this.lang, this.coder.getValue(), this.debugInput).then(res => {
        this.$Spin.hide();
        this.debugOutput = res.result;
        this.$Message.success("代码已成功运行");
      }).catch(e => {
        this.$Spin.hide();
        this.debugOutput = e.message;
        this.$Message.error(e.message);
      });
    },
    commit() {
      if(!getToken()) {
        this.$router.push('/login')
        return;
      }
      this.$Spin.show({
        render: (h) => {
          return h("div", [
            h("Icon", {
              class: "demo-spin-icon-load",
              props: {
                type: "ios-loading",
                size: 50,
              },
            }),
            h("div", { class: "textSty" }, "代码正在努力运行中"),
          ]);
        },
      });
      saveCommit(this.$route.query.id, this.lang, this.coder.getValue()).then(res => {
        if(res.result.status === 1) {
          MessageBox({
            title: '运行通过',
            message: "代码已成功通过所有样例~！",
          });
        }
        if(res.result.status === 2) {
          MessageBox.alert('<pre>' + res.result.error + '</pre>', '输出不正确', {
            dangerouslyUseHTMLString: true
          });
        }
        if(res.result.status === 3) {
          MessageBox.alert('<pre>' + res.result.error + '</pre>', '运行错误', {
            dangerouslyUseHTMLString: true
          });
        }
        if(res.result.status === 4) {
          MessageBox.alert('<pre>' + res.result.error + '</pre>', '超出时间限制', {
            dangerouslyUseHTMLString: true
          });
        }
        if(res.result.status === 5) {
          MessageBox.alert('<pre>' + res.result.error + '</pre>', '超出内存限制', {
            dangerouslyUseHTMLString: true
          });
        }
        this.$Spin.hide();
        this.$parent.$parent.$parent.getCommitPage()
      }).catch(e => {
        this.$Spin.hide();
        this.$Message.error(e.message);
        this.$parent.$parent.$parent.getCommitPage()
      });
    }
  }
}
</script>
<style>
.CodeMirror {
  border: 1px solid #eee;height: auto !important;/*min-height: 100px;*/
}
.CodeMirror-scroll {
  height: auto !important;min-height: 350px;/*overflow-y: hidden;*//*overflow-x: auto;*/
}
.common-editor {
  width: 100%;
  height: 100%;
  .CodeMirror {
    // color: #ccc;
    direction: ltr;
    line-height: 20px;
    width: 100%;
    height: 100%;
    // background-color: #000;
  }

  .CodeMirror-hints {
    z-index: 9999 !important;
  }
  .custom-class .CodeMirror {
    width: 100%;
  }
}
.CodeMirror-hints {
  z-index: 1000;
}
</style>
